/*
 * Copyright:  2018 smarabbit studio.
 *
 *  Licensed under the Confluent Community License; you may not use this file
 *  except in compliance with the License.  You may obtain a copy of the License at
 *
 *  http://www.confluent.io/confluent-community-license
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 *  WARRANTIES OF ANY KIND, either express or implied.  See the License for the
 *  specific language governing permissions and limitations under the License.
 *
 *  @作   者： 黄开晖 (117227773@qq.com)
 *  @日   期:  2021年6月19日
 */
package com.massyframework.beanskin.runtime.framework.installing;

import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import com.massyframework.beanskin.ModuleRuntimeException;
import com.massyframework.beanskin.assembly.Assembly;
import com.massyframework.beanskin.util.exceptioncollect.ExceptionCollectUtils;
import com.massyframework.beanskin.util.localstore.LocalStore;
import com.massyframework.beanskin.util.variables.StringVariableReplacer;

/**
 * 解密要求解析
 * @author huangkh
 *
 */
public abstract class SecureModuleParser<B> extends RequireLibraryModuleParser<B> {
	
	protected static final String SECURE         = "secure";
	protected static final String PUBLICKEY      = "publicKey";
	protected static final String X509CERT       = "x509cert";
	private   static final String ENCRYPTED      = "encrypted";
	protected static final String CLASSES        = "classes";
	protected static final String SCRIPTS        = "scripts";
	
	private final Logger logger = LoggerFactory.getLogger(SecureModuleParser.class);
	
	public SecureModuleParser(Assembly kernel, LocalStore localStore) {
		super(kernel, localStore);
	}

	@Override
	protected void doParseNode(Node node, Expression<String> expression, StringVariableReplacer replacer, B builder) {
		super.doParseNode(node, expression, replacer, builder);
		
		if (node.getNodeName().equals(SECURE)) {
			this.doParseDecryption(node.getChildNodes(), expression, replacer, builder);
		}
	}
	
	/**
	 * 解析解密要求
	 * @param node {@link NodeList}
	 * @param expression {@link Expression}，表达式
	 * @param replacer {@link StringVariableReplacer}, 字符变量替换器
	 * @param builder {@link B},构建器
	 */
	protected void doParseDecryption(NodeList nodes, Expression<String> expression, 
			StringVariableReplacer replacer, B builder) {
		int size = nodes.getLength();
		
		try {
			String publicKey = null;
			Certificate cert = null;
			List<String> classNames = null;
			List<String> scriptFileNames = null;
			
			for (int i=0; i<size; i++) {
				Node node = nodes.item(i);
				
				String name = node.getNodeName();
				if (PUBLICKEY.equals(name)) {
					publicKey = this.getTextContent(node);
					continue;
				}
				
				if (X509CERT.equals(name)) {
					cert = this.getCertificationValue(node);
					continue;
				}
				
				if (CLASSES.equals(name)) {
					classNames = this.getChildNodeValue(node, "name");
					continue;
				}
				
				if (SCRIPTS.equals(name)) {
					scriptFileNames = this.getChildNodeValue(node, "name");
				}
			}
			
			if (publicKey != null && classNames != null) {
				this.setDecryption(publicKey, 
						cert == null ? null : cert.getName(),
						cert == null ? null : cert.getData(),
						classNames, scriptFileNames, builder);
			}
		}catch(Exception e) {
			if (logger.isErrorEnabled()) {
				logger.error(e.getMessage(), e);
			}
			
			ExceptionCollectUtils.addException(new ModuleRuntimeException(this.getModuleIdentifier(), e));
		}
	}
	
	protected Certificate getCertificationValue(Node node) {
		NodeList nodes = node.getChildNodes();
		int size = nodes.getLength();
		
		String name = null;
		String encrypted = null;
		for (int i=0; i<size; i++) {
			Node child = nodes.item(i);
			String nodeName = child.getNodeName();
			if (NAME.equals(nodeName)) {
				name = this.getTextContent(child);
				continue;
			}
			
			if (ENCRYPTED.equals(nodeName)) {
				encrypted = this.getTextContent(child);
				continue;
			}
		}
		
		return new Certificate(name,encrypted);
	}
		
	/**
	 * 设置解密要求
	 * @param publicKey {@link String},公钥
	 * @param certificateName {@link String},证书名称
	 * @param certificateData {@link String},证书数据
	 * @param classNames {@link List},要解密的类名
	 * @param scrptFileNames {@link List}, 要解密的脚本文件
	 * @param builder {@link B}
	 */
	protected abstract void setDecryption(String publicKey, String certificateName, 
			String certificateData, List<String> classNames, List<String> scriptFileNames, B builder);
	
	
	private class Certificate {
		private String name;
		private String data;
		
		public Certificate(String name, String data) {
			this.name = name;
			this.data = data;
		}
		
		public String getName() {
			return this.name;
		}
		
		public String getData() {
			return this.data;
		}
	}
}
